/**
 * 
 */
package xj.toolkit.ebus.unit;

import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import xj.toolkit.ebus.EventBus;
import xj.toolkit.unit.UnitAdmin;
import xj.toolkit.util.PackageUtils;

/**
 * @author hp
 * 
 */
public class PropertiesEventUnitImpl implements EventUnit, UnitSourceAware {

	private static final Logger LOG = LoggerFactory.getLogger(PropertiesEventUnitImpl.class);

	private UnitSource source;
	private String[] xmlLocations;
	private UnitAdmin unitAdmin;

	public PropertiesEventUnitImpl(UnitSource source, String[] xmlLocations) {
		this.source = source;
		this.xmlLocations = xmlLocations;
	}

	public PropertiesEventUnitImpl setUnitAdmin(final UnitAdmin unitAdmin) {
		this.unitAdmin = unitAdmin;
		return this;
	}

	/**
	 * @see com.skymobi.ebus.unit.EventUnit#init(com.skymobi.ebus.EventBus)
	 */
	@Override
	public Object init(final EventBus eventBus) {
		if (LOG.isDebugEnabled()) {
			LOG.debug("current thread contextClassLoader {}", Thread.currentThread().getContextClassLoader());
		}

		final String springXml = searchSpringXml(getTemplateFromSourceName(source.getTemplate()));

		if (null == springXml) {
			LOG.error("!CAN'T! found matched spring config xml, failed to create unit name[{}], template[{}]",
					source.getName(), source.getTemplate());
			return null;
		}

		if (null != this.unitAdmin) {
			InputStream in = null;
			try {
				final Properties props = source.getExtendsProperties();
				in = source.getInputStream();
				if (in != null) {
					props.load(in);
				}
				return this.unitAdmin.createUnit("default", source.getName(), springXml, new HashMap<String, String>() {
					private static final long serialVersionUID = 1L;

					{
						for (Map.Entry<Object, Object> entry : props.entrySet()) {
							this.put(entry.getKey().toString(), entry.getValue().toString());
						}
					}
				});
			} catch (Exception e) {
				LOG.error("exception when createUnit for source {}, detail: {}", source.getTemplate(), e.getMessage());
				LOG.error("detail exception.", e);
			} finally {
				IOUtils.closeQuietly(in);
			}
		}

		return null;
	}

	/**
	 * @return
	 */
	private String getTemplateFromSourceName(final String sourceName) {
		String template = FilenameUtils.getBaseName(sourceName);
		int idx = template.lastIndexOf(".");
		if (-1 != idx) {
			template = template.substring(idx + 1);
		}
		return template;
	}

	@Override
	public void destroy(Object ctx) {
		if (null != ctx) {
			((UnitAdmin.UnitMXBean) ctx).close();
		}
	}

	@Override
	public String getDescription() {
		return source.getName();
	}

	public void setUnitSource(UnitSource source) {
		this.source = source;
	}

	private String searchSpringXml(final String template) {
		for (String location : this.xmlLocations) {
			try {
				if (LOG.isTraceEnabled()) {
					LOG.trace("start search resource in {}", location);
				}
				String[] allRes = PackageUtils.getResourceInPackage(location);
				for (String res : allRes) {
					if (LOG.isTraceEnabled()) {
						LOG.trace("found resource: {}", res);
					}
					if (res.endsWith("." + template + ".xml")) {
						if (LOG.isDebugEnabled()) {
							LOG.debug("found matched spring config: {}", res);
						}

						return res.substring(0, res.length() - 4).replace('.', '/') + ".xml";
					}
				}
			} catch (IOException e) {
				LOG.error("invalid xmlPath {}", location, e);
			}
		}

		return null;
	}

}
